package jmvm.schemes;



import java.awt.Point;
import java.util.ArrayList;

import jmvm.components.*;
import jmvm.gui.GuiLabel;
import jmvm.gui.GuiLine;
import jmvm.gui.GuiScheme;


public class Bus {

	public static IntToInt IBUS_L;
	//////////////////////////////////public static BUS IBUS_L;
	
	public static BoolsToInt DW;
	public static IntToBools DW_HBits, DW_LBits;
	
	public static BUS IBUS, DBUS, ABUS, NotRDBUS, NotWRBUS, NotFCBUS;
	public static MP MX2;
	public static REG MAR, MDR, DW_H, DW_L;
	public static NOT fcCPU, NOT_eMar;
	public static AND AND1, AND2;
	public static OR OR1;
	
	public static TSB MDRout, eMAR, eMDR, rdCPU, wrCPU, DWout;
	
	private static int IBUSi=0, DBUSi=0, ABUSi=0, NotRDBUSi=0, NotWRBUSi=0, NotFCBUSi=0 ;
	//
	
	public static NOT not_fcCPU;
	
	////////////
	//////////// Grafika
	////////////
	
	public static GuiScheme gui;

	public static GuiScheme getGui() {
		return gui;
	}
	
	public static void gui() {

		GuiLine line; // Pomocna promenljiva
		gui = new GuiScheme("jmvm/jmvm/images/bus.png");
		
		ArrayList<ArrayList<Point>> sections;
		ArrayList<Point> points;
		
		// 
		// 
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(614,3));
		points.add(new Point(614,759));
		points.add(new Point(612,759));
		points.add(new Point(612,3));
		sections.add(points);
		line=new GuiLine(sections,Bus.IBUS());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(169,193));
		points.add(new Point(169,45));
		points.add(new Point(612,45));
		sections.add(points);
		line=new GuiLine(sections,Bus.IBUS());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(497,46));
		points.add(new Point(497,118));
		sections.add(points);
		line=new GuiLine(sections,Bus.IBUS());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(476,96));
		points.add(new Point(476,118));
		sections.add(points);
		line=new GuiLine(sections,Bus.DBUS());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(487,163));
		points.add(new Point(487,192));
		sections.add(points);
		line=new GuiLine(sections,MX2.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(531,289));
		points.add(new Point(612,289));
		sections.add(points);
		line=new GuiLine(sections,MDRout.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(487,237));
		points.add(new Point(487,352));
		sections.add(points);
		line=new GuiLine(sections,MDR.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(487,289));
		points.add(new Point(504,289));
		sections.add(points);
		line=new GuiLine(sections,MDR.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(487,379));
		points.add(new Point(487,398));
		sections.add(points);
		line=new GuiLine(sections,eMDR.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(169,237));
		points.add(new Point(169,352));
		sections.add(points);
		line=new GuiLine(sections,MAR.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(612,572));
		points.add(new Point(169,572));
		points.add(new Point(169,592));
		sections.add(points);
		line=new GuiLine(sections,Bus.IBUS());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(487,573));
		points.add(new Point(487,592));
		sections.add(points);
		line=new GuiLine(sections,Bus.IBUS());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(530,693));
		points.add(new Point(612,693));
		sections.add(points);
		line=new GuiLine(sections,DWout.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(487,637));
		points.add(new Point(487,653));
		sections.add(points);
		line=new GuiLine(sections,DW_L.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(169,637));
		points.add(new Point(169,655));
		sections.add(points);
		line=new GuiLine(sections,DW_H.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(465,693));
		points.add(new Point(504,693));
		sections.add(points);
		line=new GuiLine(sections,DW.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(322,199));
		points.add(new Point(322,215));
		points.add(new Point(329,215));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.rdCPU());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(363,200));
		points.add(new Point(363,208));
		points.add(new Point(372,208));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.ldMDR());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(384,289));
		points.add(new Point(390,289));
		points.add(new Point(390,257));
		points.add(new Point(322,257));
		points.add(new Point(322,228));
		points.add(new Point(329,228));
		sections.add(points);
		line=new GuiLine(sections,fcCPU());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(356,221));
		points.add(new Point(372,221));
		sections.add(points);
		line=new GuiLine(sections,AND1.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(363,229));
		points.add(new Point(363,222));
		sections.add(points);
		line=new GuiLine(sections,AND1.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(397,215));
		points.add(new Point(403,215));
		sections.add(points);
		line=new GuiLine(sections,OR1.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(169,378));
		points.add(new Point(169,397));
		sections.add(points);
		line=new GuiLine(sections,eMAR.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(56,457));
		points.add(new Point(67,457));
		sections.add(points);
		line=new GuiLine(sections,new Pin(true));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(99,457));
		points.add(new Point(106,457));
		sections.add(points);
		line=new GuiLine(sections,Bus.NotRDBUS());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(250,457));
		points.add(new Point(261,457));
		sections.add(points);
		line=new GuiLine(sections,new Pin(true));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(293,457));
		points.add(new Point(299,457));
		sections.add(points);
		line=new GuiLine(sections,Bus.NotWRBUS());
		gui.addLine(line);

		//
		//
		// 
		// 
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(345,289));
		points.add(new Point(352,289));
		sections.add(points);
		line=new GuiLine(sections,Bus.NotFCBUS());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(477,464));
		points.add(new Point(483,464));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.eMAR());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(515,457));
		points.add(new Point(522,457));
		sections.add(points);
		line=new GuiLine(sections,AND2.getOut(0));
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(526,140));
		points.add(new Point(519,140));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.mxMDR0());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(78,204));
		points.add(new Point(86,204));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.ldMAR());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(78,225));
		points.add(new Point(86,225));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.incMAR());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(518,303));
		points.add(new Point(518,295));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.MDRout());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(473,366));
		points.add(new Point(481,366));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.eMDR());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(156,366));
		points.add(new Point(163,366));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.eMAR());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(80,470));
		points.add(new Point(80,463));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.rdCPU());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(274,471));
		points.add(new Point(274,464));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.wrCPU());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(79,625));
		points.add(new Point(86,625));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.ldDWH());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(396,625));
		points.add(new Point(403,625));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.ldDWL());
		gui.addLine(line);

		//
		//
		sections=new ArrayList<ArrayList<Point>>();
		points=new ArrayList<Point>();
		points.add(new Point(518,706));
		points.add(new Point(518,700));
		sections.add(points);
		line=new GuiLine(sections,UpravOper.DWout());
		gui.addLine(line);

		//
		//
		gui.addLabel(new GuiLabel(585, 66, Bus.IBUS()));
		gui.addLabel(new GuiLabel(467, 85, Bus.DBUS()));
		gui.addLabel(new GuiLabel(493, 179, MX2.getOut(0)));
		gui.addLabel(new GuiLabel(473, 278, MDR.getOut(0)));
		gui.addLabel(new GuiLabel(174, 286, MAR.getOut(0)));
		gui.addLabel(new GuiLabel(164, 666, DW_H.getOut(0)));
		gui.addLabel(new GuiLabel(485, 666, DW_L.getOut(0)));


		
	}
	/////////////
	/////////////
	/////////////
	
	public static void init() {
	
		////
		IBUS_L = new IntToInt(16,8,false,false);
		///////////IBUS_L = new BUS(1,1,"IBUS_L");
		////////////////IBUS_L.getOut(0).setNumOfLines(8);
		DW = new BoolsToInt(16, 16);
		DW_HBits = new IntToBools(8,8);
		DW_LBits = new IntToBools(8,8);
		////
		
		//////////////////////////////// BUSES

		IBUS = new BUS(40,1,"IBUS");
		IBUS.getOut(0).setNumOfLines(16);
		DBUS = new BUS(16,1,"DBUS");
		DBUS.getOut(0).setNumOfLines(8);
		ABUS = new BUS(16,1,"ABUS");
		ABUS.getOut(0).setNumOfLines(16);
		NotRDBUS = new BUS(16,1, "NotRDBUS");
		NotRDBUS.getOut(0).setIsBool();
		NotWRBUS = new BUS(16,1, "NotWRBUS");
		NotWRBUS.getOut(0).setIsBool();
		NotFCBUS = new BUS(16,1, "NotFCBUS");
		NotFCBUS.getOut(0).setIsBool();
		
		///////////////////////////////// MUX
		
		MX2 = new MP(2);
		MX2.getOut(0).setIsInt();
		MX2.getOut(0).setNumOfLines(8);
		
		///////////////////////////////// REGS
		
		MAR = new REG(1,"MAR");
		MAR.getOut(0).setIsInt();
		MAR.getOut(0).setNumOfLines(16);
		MDR = new REG(1,"MDR");
		MDR.getOut(0).setIsInt();
		MDR.getOut(0).setNumOfLines(8);
		DW_H = new REG(1,"DW_H");
		DW_H.getOut(0).setIsInt();
		DW_H.getOut(0).setNumOfLines(8);
		DW_L = new REG(1,"DW_L");
		DW_L.getOut(0).setIsInt();
		DW_L.getOut(0).setNumOfLines(8);
		
		//////////////////////////////////
		
		fcCPU = new NOT();
		NOT_eMar = new NOT();
		AND1=new AND();
		AND2=new AND();
		OR1=new OR();
		
		////////////////////////////////// TSBs
		
		MDRout=new TSB();
		MDRout.getOut(0).setNumOfLines(8);
		eMAR=new TSB();
		eMAR.getOut(0).setNumOfLines(16);
		eMDR=new TSB();
		eMDR.getOut(0).setNumOfLines(8);
		rdCPU=new TSB();
		rdCPU.getOut(0).setNumOfLines(1);
		rdCPU.getOut(0).setIsBool();
		wrCPU=new TSB();
		wrCPU.getOut(0).setNumOfLines(1);
		wrCPU.getOut(0).setIsBool();	
		DWout=new TSB();
		DWout.getOut(0).setNumOfLines(16);
		
		///
		not_fcCPU = new NOT();
	}
	
	public static void connect(){
		
		/////
		IBUS_L.setInputPin(0, IBUS.getOut(0));
		DW_HBits.setInputPin(0, DW_H.getOut(0));
		DW_LBits.setInputPin(0, DW_L.getOut(0));
		for (int i = 0; i < 8; i++) {
			DW.setInputPin(i, DW_LBits.getOut(i));
			DW.setInputPin(8 + i, DW_HBits.getOut(i));
		}
		/////
		
		MX2.setInputPin(0, DBUS.getOut(0));
		MX2.setInputPin(1, IBUS_L.getOut(0));
		MX2.setCtrl(0, UpravOper.mxMDR0());
		
		///////////////////////////////////
		
		MAR.setInputPin(0, IBUS.getOut(0));
		MAR.setPinLd(UpravOper.ldMAR());
		MAR.setPinInc(UpravOper.incMAR());
		
		MDR.setInputPin(0, MX2.getOut(0));
		MDR.setPinLd(OR1.getOut(0));
		
		DW_H.setInputPin(0, IBUS_L.getOut(0));
		DW_H.setPinLd(UpravOper.ldDWH());
		
		DW_L.setInputPin(0, IBUS_L.getOut(0));
		DW_L.setPinLd(UpravOper.ldDWL());
		
		///////////////////////////////////////
		
		fcCPU.setInputPin(0, NotFCBUS.getOut(0));
		
		AND1.setInputPin(0, UpravOper.rdCPU());
		AND1.setInputPin(1, fcCPU.getOut(0));
		
		// U/I treba li???????????????????
		NOT_eMar.setInputPin(0, UpravOper.eMAR());
		AND2.setInputPin(0, new Pin(false));
		AND2.setInputPin(1, NOT_eMar.getOut(0));
		// U/I treba li???????????????????
		
		OR1.setInputPin(0, UpravOper.ldMDR());
		OR1.setInputPin(1, AND1.getOut(0));
		
		///////////////////////////////////////// TSB MDRout, eMAR, eMDR, rdCPU, wrCPU, DWout;
		
		MDRout.setInputPin(0, MDR.getOut(0));
		MDRout.setCtrl(UpravOper.MDRout());
		Bus.addOnIBUS(MDRout.getOut(0));
		
		eMAR.setInputPin(0, MAR.getOut(0));
		eMAR.setCtrl(UpravOper.eMAR());
		Bus.addOnABUS(eMAR.getOut(0));
		
		eMDR.setInputPin(0, MDR.getOut(0));
		eMDR.setCtrl(UpravOper.eMDR());
		Bus.addOnDBUS(eMDR.getOut(0));
		
		rdCPU.setInputPin(0, new Pin(false));
		rdCPU.setCtrl(UpravOper.rdCPU());
		Bus.addOnNotRDBUS(rdCPU.getOut(0));			// IZMENJENO
		
		wrCPU.setInputPin(0, new Pin(false));
		wrCPU.setCtrl(UpravOper.wrCPU());
		Bus.addOnNotWRBUS(wrCPU.getOut(0));			// IZMENJENO
		
		DWout.setInputPin(0, DW.getOut(0));
		DWout.setCtrl(UpravOper.DWout());
		Bus.addOnIBUS(DWout.getOut(0));
				
		not_fcCPU.setInputPin(0, fcCPU.getOut(0));
	}
	
	
	public static void addOnIBUS(Pin pin) {
		IBUS.setInputPin(IBUSi++, pin);	
	}
	public static void addOnDBUS(Pin pin) {
		DBUS.setInputPin(DBUSi++, pin);	
	}
	public static void addOnABUS(Pin pin) {
		ABUS.setInputPin(ABUSi++, pin);
	}
	public static void addOnNotRDBUS(Pin pin) {
		NotRDBUS.setInputPin(NotRDBUSi++, pin);	
	}
	public static void addOnNotWRBUS(Pin pin) {
		NotWRBUS.setInputPin(NotWRBUSi++, pin);
	}
	public static void addOnNotFCBUS(Pin pin) {
		NotFCBUS.setInputPin(NotFCBUSi++, pin);
	}
	public static Pin IBUS() { 
		return IBUS.getOut(0); 
	}
	
	public static Pin IBUS_L() {
		return IBUS_L.getOut(0); 
	}

	public static Pin DBUS() {
		return DBUS.getOut(0);
	}

	public static Pin ABUS() {
		return ABUS.getOut(0);
	}

	public static Pin NotRDBUS() {
		return NotRDBUS.getOut(0);
	}

	public static Pin NotWRBUS() {
		return NotWRBUS.getOut(0);
	}

	public static Pin NotFCBUS() {
		return NotFCBUS.getOut(0);
	}

	public static Pin hack() {
		return AND2.getOut(0);
	}

	public static Pin not_fcCPU() {
		return not_fcCPU.getOut(0);
	}
	
	public static Pin fcCPU() {
		return fcCPU.getOut(0);
	}
	
	public static void ispisiRegistre() {
		System.out.println(" Registri:" + " MAR=" + MAR.getOut(0).getIntVal() + " MDR=" + MDR.getOut(0).getIntVal() 
				+ " DW_H=" + DW_H.getOut(0).getIntVal() + " DW_L=" + DW_L.getOut(0).getIntVal() );
	}
	
}
